/*
============================================================================
 Name        : SMSEngine.cpp
 Author      : chenzs
 Version     :
 Copyright   : Joyhoo.com 2007-2008
 Description : CSMSEngine implementation
============================================================================
*/

#include "SMSEngine.h"
#include  <msvids.h>
#include <smut.h>
#include <mtmdef.h>
#include <TXTRICH.H> //CRichText, link etext.lib 
#include <smuthdr.h> //CSmsHeader
#include <SMUTSET.H> //CSmsSttings
#include <smscmds.h>
#include <Gsmumsg.h>


// -----------------------------------------------------------------------------
// ::NewL()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSMSEngine* CSMSEngine::NewL(MSmsEngineObserver *pObserver)
{
    CSMSEngine* self = NewLC(pObserver);
    CleanupStack::Pop( self );
    return self;
}

// -----------------------------------------------------------------------------
// ::NewLC()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSMSEngine* CSMSEngine::NewLC(MSmsEngineObserver *pObserver)
{
    CSMSEngine* self = new ( ELeave ) CSMSEngine();
    CleanupStack::PushL( self );
    self->ConstructL(pObserver);
    return self;
}

CSMSEngine::CSMSEngine() : CActive(EPriorityStandard)	// Standard priority
{
	CActiveScheduler::Add(this);				// Add to scheduler
}

void CSMSEngine::ConstructL(MSmsEngineObserver *pObserver)
{
	// Session to message server is opened asynchronously.
	m_pObserver = pObserver;
    m_pSession = CMsvSession::OpenAsyncL( *this );
}

CSMSEngine::~CSMSEngine()
{
	Cancel(); // Cancel any request, if outstanding
	// Delete instance variables 
	delete m_pOperation;
   	delete m_pSmsMtm;
    delete m_pMtmRegistry;
    delete m_pSession;    // session must be deleted last
}

void CSMSEngine::DoCancel()
{
	if ( m_pOperation )
    {
		m_pOperation->Cancel();
    }
}


void CSMSEngine::RunL()
{
	if( iStatus != KErrNone )
		return;

    // Determine the current operations progress.
    // ProgressL returns an 8 bit descriptor.
    TBufC8<KMsvProgressBufferLength> progress( m_pOperation->ProgressL() );
    _LIT8( KCompare, "KErrNone" );
    User::LeaveIfError( !progress.Compare( KCompare ) );

    // The pointer to the current CMsvOperation object is no longer needed.
    if(m_pOperation)
	{
		delete m_pOperation;
		m_pOperation = NULL;
	}

    // Determine which request has finished.
    switch ( iState )
        {
        case EWaitingForMoving:
            // Once a message is moved to Outbox it is scheduled for sending.
            ScheduleL();
            break;
       case EWaitingForScheduling:
            {
          /*  TMsvEntry entry(m_pSmsMtm->Entry().Entry() );
            TInt state( entry.SendingState() );

            if ( state == KMsvSendStateWaiting || state == KMsvSendStateScheduled)
                {
                HBufC* text = StringLoader::LoadLC( R_SMS_MOVED_TO_OUTBOX );
                CAknInformationNote* informationNote =
                    new ( ELeave ) CAknInformationNote;
                informationNote->ExecuteLD( *text );
                CleanupStack::PopAndDestroy( text );
                }
		 */

            break;
			}
        default:
            break;
        }
}

/**
* ScheduleL.
* Schedule an SMS message for sending.
*/
void CSMSEngine::ScheduleL()
{
	CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
    CleanupStack::PushL( selection );
    selection->AppendL( m_pSmsMtm->Entry().EntryId() ); // add message to selection

    // Add entry to task scheduler.
    TBuf8<1> dummyParams;   // dummy parameters needed for InvokeAsyncFunctionL
    m_pOperation = m_pSmsMtm->InvokeAsyncFunctionL( ESmsMtmCommandScheduleCopy,
                          *selection, dummyParams, iStatus );

    CleanupStack::PopAndDestroy( selection );

    iState = EWaitingForScheduling;
    SetActive();
}

/**
 * ���ⲿ���ã����Ͷ���
 */
TBool CSMSEngine::SendL( const TDesC& aRecipientNumber, const TDesC& aMessageText )
{
	if(!m_pSmsMtm)
		return EFalse;

	// Current entry is the Draft folder.
    m_pSmsMtm->SwitchCurrentEntryL( KMsvDraftEntryId );

    // Create a new SMS message entry as a child of the current context.
    m_pSmsMtm->CreateMessageL( KUidMsgTypeSMS.iUid );

    CMsvEntry& serverEntry = m_pSmsMtm->Entry();
    TMsvEntry entry( serverEntry.Entry() );

    CRichText& body = m_pSmsMtm->Body();   // the body of the message
    body.Reset();
    // Insert the message text gotten as input from user.
    body.InsertL( 0, aMessageText );

    // Message will be sent immediately.
    entry.SetSendingState( KMsvSendStateWaiting );
	
	entry.iDate.UniversalTime();//ʱ������3rd
	//entry.iDate.HomeTime(); // insert current time 2nd

    // Set the SMS message settings for the message.
    CSmsHeader& header = m_pSmsMtm->SmsHeader();
    CSmsSettings* settings = CSmsSettings::NewL();
    CleanupStack::PushL( settings );

    settings->CopyL( m_pSmsMtm->ServiceSettings() );    // restore settings
    settings->SetDelivery( ESmsDeliveryImmediately ); // to be delivered immediately
    header.SetSmsSettingsL( *settings );              // new settings

	// Let's check if there is a service center address.
	if ( header.Message().ServiceCenterAddress().Length() == 0 )
	{
		// No, there isn't. We assume there is at least one service center
        // number set and use the default service center number.
		CSmsSettings* serviceSettings = &( m_pSmsMtm->ServiceSettings() );

        // Check if number of service center addresses in the list is null.
        if ( !serviceSettings->ServiceCenterCount() )
        {
            // Remember to pop settings even if this branch is taken.
            CleanupStack::PopAndDestroy( settings );
			return EFalse;     // quit creating the message
        }
		else
		{
            // Set service center address to default.
            // The caller does not take ownership of the returned object.
            CSmsServiceCenter* smsCenter = &( serviceSettings->GetServiceCenter( serviceSettings->DefaultServiceCenter()) );
			header.Message().SetServiceCenterAddressL( smsCenter->Address() );
		}
    }
	CleanupStack::PopAndDestroy( settings );

    // Recipient number is displayed also as the recipient alias.
    entry.iDetails.Set( aRecipientNumber );
    // Add addressee.
    m_pSmsMtm->AddAddresseeL( aRecipientNumber, entry.iDetails );

    // Validate message.
    if ( !ValidateL() )
        {
        return EFalse;
        }

    entry.SetVisible( ETrue );          // set message as visible
    entry.SetInPreparation( EFalse );   // set together with the visibility flag
    serverEntry.ChangeL( entry );       // commit changes
    m_pSmsMtm->SaveMessageL();            // save message

    TMsvSelectionOrdering selection;
	CMsvEntry* parentEntry =
        CMsvEntry::NewL( m_pSmsMtm->Session(), KMsvDraftEntryId, selection );
    CleanupStack::PushL( parentEntry );

    // Move message to Outbox.
    m_pOperation =
        parentEntry->MoveL( entry.Id(), KMsvGlobalOutBoxIndexEntryId, iStatus );

    CleanupStack::PopAndDestroy( parentEntry );

    iState = EWaitingForMoving;
    SetActive();

    return ETrue;
}

// -----------------------------------------------------------------------------
// CSMSEngine::ValidateL()
// ��֤������Ч��
// -----------------------------------------------------------------------------
//
TBool CSMSEngine::ValidateL()
{
	// Empty part list to hold the result.
	TMsvPartList result( KMsvMessagePartNone );

	// Validate message body.
	result = m_pSmsMtm->ValidateMessage( KMsvMessagePartBody );

	if ( result != KMsvMessagePartNone )
	{
		return EFalse;
	}

	// Validate recipient.
	result = m_pSmsMtm->ValidateMessage( KMsvMessagePartRecipient );

	if ( result != KMsvMessagePartNone )
	{
		return EFalse;
	}

	return ETrue;
}


// -----------------------------------------------------------------------------
// CSMSEngine::HandleSessionEventL()
// Handles notifications of events from the Message Server.
// -----------------------------------------------------------------------------
//
void CSMSEngine::HandleSessionEventL( TMsvSessionEvent aEvent,
                                      TAny* aArg1, TAny* aArg2, TAny* /*aArg3*/)
{
	switch ( aEvent )
		{
        // Session to server established
		case EMsvServerReady:
            {
            TMsvId serviceId( KUidMsgTypeSMS.iUid ); // SMS service id

            // Determine if the event was succesful.
            // ServiceProgress inserts TBuf8 value in progress.
            TBuf8<20> progress;
			m_pSession->ServiceProgress( serviceId, progress );
			_LIT8( KCompare, "KErrNone" );

			if ( progress.Compare( KCompare ) )
			{
                // Check that MtmRegistry has not already been accessed.
                if ( !m_pMtmRegistry )
                {
                    AccessMtmL();
                }
            }
            else
			{
				//error
            }
            break;
            }

        // A new entry has been created on the message server.
        case EMsvEntriesCreated:
            {
            //// Entry id is obtained from the session event arguments.
            //TMsvId* entryId = STATIC_CAST( TMsvId*, aArg2 );

            //// We are interested in messages that are created in Inbox.
            //if ( *entryId != KMsvGlobalInBoxIndexEntryId )
            //{
            //    break;
            // }
            //// We take the created entries into a selection
            //CMsvEntrySelection* newEntries =
            //    STATIC_CAST( CMsvEntrySelection*, aArg1 );

            // Process each created entry.
            //for ( TInt i( 0 ); i < newEntries->Count(); i++ )
            //    {
            //    // We are interested in SMS messages.
            //    if ( ( iSession->GetEntryL( newEntries->At( i ) ) )
            //        ->Entry().iMtm == KUidMsgTypeSMS )
            //        {
            //        // Add the entry to the selection of all received messages.
            //        iSelection->AppendL( newEntries->At( i ), 1 );

            //        // Set received messages visible.
            //        MessageReceivedL( newEntries->At( i ) );
            //        }
            //    }

            break;
            }

        case EMsvCloseSession:
        case EMsvServerTerminated:
        {
        	m_pObserver->SMSEngineEvent(ETypeSendFinished);	//<update 2009'1.18, need check>
        	break;
        }
        case EMsvGeneralError:
        case EMsvServerFailedToStart:
            {
            	m_pObserver->SMSEngineEvent(ETypeSendFinished);	//<update 2009'1.18, need check>
            	break;
            }

        // All other events are ignored.
        default:
            break;
        }
}

/////////////////////////////////////////////////////////////////////////////
//AccessMtmL.
// Access the MTM Registry and create an SMS specific Client MTM instance.
/////////////////////////////////////////////////////////////////////////////
void CSMSEngine:: AccessMtmL()
{
	 // Create an MTM Registry object.
    m_pMtmRegistry = CClientMtmRegistry::NewL( *m_pSession );
	
	// Create an SMS Client MTM object.
    m_pSmsMtm = static_cast<CSmsClientMtm*>(m_pMtmRegistry->NewMtmL( KUidMsgTypeSMS ) );
}


